package com.juhuixing.common.utils.date;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author lk
 * @date 2018年06月12日
 * @modify by 刘猛（废弃传统的SimpleDateFormat--线程不安全，效率慢，内存开销大）
 */
public class DateUtil {

    public static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
    public static final String yyyyMMddHHmmss = "yyyy年MM月dd日 HH时mm分ss秒";
    public static final String yyyyMMddHHmm = "yyyy年MM月dd日 HH:mm";
    public static final String yyyy_MM_dd = "yyyy-MM-dd";

    public static final String yyyy_MM = "yyyy-MM";

    public static final String A_HH_MM = "a HH:mm";

    public static final String DAY_START = " 00:00:00";
    public static final String DAY_END = " 59:59:59";

    /**
     * 2个String类型的日期进行比较（天）
     *
     * @param beginString 时间
     * @param endString   比较时间
     * @return 是否小于比较时间
     */
    public static boolean isBefore(String beginString, String endString) {
        boolean status = false;
        try {
            Date bt = DateUtils.parseDate(beginString,yyyy_MM_dd);
            Date et = DateUtils.parseDate(endString,yyyy_MM_dd);
            if (bt.before(et)) {
                status = true;
            }
        } catch (Exception e) {

        }
        return status;
    }

    public static String format(Date date, String pattern) {
        return DateFormatUtils.format(date,pattern);
    }

    public static Date formatDate(String pattern){
        Date d = null;
        try {
            d = DateUtils.parseDate(pattern,yyyy_MM_dd);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return d;
    }

    /**
     * 10位时间戳和13位时间戳格式
     *
     * @param str_num 时间字符串
     * @param format  时间格式
     * @return string型的时间
     * @author 刘凯
     * @date 2018-07-01
     */
    public static String timestamp2Date(String str_num, String format) {
        if (str_num.length() == 13) {
            String date = DateFormatUtils.format(new Date(Long.parseLong(str_num)),format);
            return date;
        } else {
            String date = DateFormatUtils.format(new Date(Integer.parseInt(str_num) * 1000L),format);
            return date;
        }
    }

    /**
     * 根据系统时间获取昨天日期
     *
     * @return 昨天Date
     */
    public static Date getYesterday() {
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        //把日期往后增加一天.整数往后推,负数往前移动
        calendar.add(Calendar.DATE, -1);
        return calendar.getTime();
    }

    /**
     * 获取当期日期前day天的日期
     * @param day
     * @return
     */
    public static Date getAppointday(int day) {
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        //把日期往后增加一天.整数往后推,负数往前移动
        calendar.add(Calendar.DATE, -day);
        return calendar.getTime();
    }

    public static String getYesterdayToString(){
        SimpleDateFormat sdf = new SimpleDateFormat(yyyy_MM_dd);
        return sdf.format(getYesterday());
    }

    public static String getAppointdayToString(int day){
        return DateFormatUtils.format(getAppointday(day),yyyy_MM_dd);
    }

    public static String getNowDate(){
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        return DateFormatUtils.format(calendar.getTime(),yyyy_MM_dd);
    }

    public static String getTime(){
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        return DateFormatUtils.format(calendar.getTime(),yyyy_MM_dd_HH_mm_ss);
    }


    /**
     * 1:周日  2：周一  3：周二
     * @return
     */
    public static int getWeekDay(){
        Date today = new Date();
        Calendar c=Calendar.getInstance();
        c.setTime(today);
        int weekday=c.get(Calendar.DAY_OF_WEEK);
        return weekday;
    }


    /**
     * 根据系统时间获取明天日期
     *
     * @return 昨天Date
     */
    public static Timestamp getTomorrow(Timestamp timestamp) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(new Date(timestamp.getTime()));
        //把日期往后增加一天.整数往后推,负数往前移动
        calendar.add(Calendar.DATE, 1);
        calendar.get(Calendar.MONTH);
        return new Timestamp(calendar.getTime().getTime());
    }

    public static Date parse(String dateString) {
        Date date = null;
        try {
            date = DateUtils.parseDate(dateString,yyyy_MM_dd_HH_mm_ss);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 功能描述: 获取时间的月份
     * @methodName getMonth
     * @author: 刘猛
     * @date: 2019/5/16 15:55
     * @param: [dateString, pattern]
     * @return: java.lang.Integer
     **/
    public static Integer getMonth(String dateString,String pattern){
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(DateUtil.parse(dateString,pattern));
        return calendar.get(Calendar.MONTH) + 1;
    }


    public static Date parse(String dateString,String pattern) {
        Date date = null;
        try {
            date = DateUtils.parseDate(dateString,pattern);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 将时间转为十分秒
     *
     * @param ms
     * @return
     */
    public static String formatTimeForDate(Long ms) {
        Integer ss = 1000;
        Integer mi = ss * 60;
        Integer hh = mi * 60;
        Integer dd = hh * 24;

        Long day = ms / dd;
        Long hour = (ms - day * dd) / hh;
        Long minute = (ms - day * dd - hour * hh) / mi;
        Long second = (ms - day * dd - hour * hh - minute * mi) / ss;
        Long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;

        StringBuffer sb = new StringBuffer();
        sb.append(day + ":");
        sb.append(hour + ":");
        sb.append(minute + ":");
        sb.append(second + ":");
        return sb.toString();
    }

    /**
     * 算昨天凌晨00:00:00 毫秒值
     */
    public static Long yesterdayWeeHours() {
        long nowTime = System.currentTimeMillis();
        Long day = nowTime / (24 * 60 * 60 * 1000);
        Long yesterdayWeeHours = (day - 1) * 24 * 60 * 60 * 1000 - 8 * 60 * 60 * 1000;
        return yesterdayWeeHours;
    }

    /**
     * 算今天凌晨00:00:00 毫秒值
     */
    public static Long getTodayWeeHours() {
        //现在的时间戳 补齐时间戳起始时间为8点的差值
        long nowTime = System.currentTimeMillis() + 8 * 60 * 60 * 1000;
        //算出天数
        Long day = nowTime / (24 * 60 * 60 * 1000);
        Long todayWeeHours = (day) * 24 * 60 * 60 * 1000 - 8 * 60 * 60 * 1000;
        return todayWeeHours;
    }

    /**
     * 将毫秒值转化成 String格式
     *
     * @param time 时间毫秒值
     * @return 返回字符串 格式 yyyy_MM_dd_HH_mm_ss
     */
    public static String formatDate(Long time) {
        return DateFormatUtils.format(time,yyyy_MM_dd_HH_mm_ss);
    }

    /**
     * 计算两个日期的差值--天
     *
     * @param oldDate
     * @param newDate
     * @return
     */
    public static int daysDifferInDay(Date oldDate, Date newDate) {

        Calendar oldCal = Calendar.getInstance();
        oldCal.setTime(oldDate);

        Calendar newCal = Calendar.getInstance();
        newCal.setTime(newDate);
        int day1 = oldCal.get(Calendar.DAY_OF_YEAR);
        int day2 = newCal.get(Calendar.DAY_OF_YEAR);

        return day2 - day1;
    }

    /**
     * 获取当前日期所在一周的开始日期和结束日期
     *
     * @param date
     * @return [0]-开始日期、[1]-结束日期
     */
    public static String[] getWeekInfo(String date) {
        LocalDate inputDay = LocalDate.parse(date);
        //一周的第一天
        TemporalAdjuster FIRST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.minusDays(localDate.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue()));
        LocalDate firstDay = inputDay.with(FIRST_OF_WEEK);
        //一周的最后一天
        TemporalAdjuster LAST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue()));
        LocalDate lastDay = inputDay.with(LAST_OF_WEEK);
        String[] weekInfo = {firstDay.toString(), lastDay.toString()};
        return weekInfo;
    }
    /**
     * 计算日期的年--天
     *
     * @param newDate
     * @return
     */
    public static int getDateYear(Date newDate) {

        Calendar newCal = Calendar.getInstance();
        newCal.setTime(newDate);
        return newCal.get(Calendar.YEAR);
    }

    /**
     * 获取当前日期所在月的开始日期和结束日期
     *
     * @param date
     * @return [0]-开始日期、[1]-结束日期
     */
    public static String[] getMonthInfo(String date) {
        LocalDate inputDay = LocalDate.parse(date);
        //一月的第一天
        LocalDate firstDay = LocalDate.of(inputDay.getYear(), inputDay.getMonth(), 1);
        //一月的最后一天
        LocalDate lastDay = inputDay.with(TemporalAdjusters.lastDayOfMonth());
        String[] monthInfo = {firstDay.toString(), lastDay.toString()};
        return monthInfo;
    }

    /**
     * 获取当前日期所在月的开始日期和结束日期
     *
     * @param date
     * @return [0]-开始日期、[1]-结束日期
     */
    public static String[] getDayInfo(String date) {
        LocalDate inputDay = LocalDate.parse(date);
        //当天零点
        LocalDateTime today_start = LocalDateTime.of(inputDay, LocalTime.MIN);
        //当天零点
        LocalDateTime today_end = LocalDateTime.of(inputDay, LocalTime.MAX);
        String[] dayInfo = {today_start.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), today_end.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))};
        return dayInfo;
    }

    public static Long Date2long(Date date){
        long time = date.getTime();
        return time;
    }

    /**
     * 获取一段时间的天数
     * @param currentDate
     * @param targetDate
     * @return
     */
    public static int days(Date currentDate, Date targetDate){
        String currentDateStr = format(currentDate, yyyy_MM_dd);
        String targetDateStr = format(targetDate, yyyy_MM_dd);
        long time = parse(currentDateStr+ " 00:00:00").getTime();
        long time1 = parse(targetDateStr+ " 00:00:00").getTime();
        return Integer.parseInt(((time-time1)/(1000L*60*60*24))+"");
    }

    /**
     * 获取当前时间点离一天结束剩余秒数
     * @param currentDate
     * @return
     */
    public static Integer getRemainSecondsOneDay(Date currentDate) {
        LocalDateTime midnight = LocalDateTime.ofInstant(currentDate.toInstant(),
                ZoneId.systemDefault()).plusDays(1).withHour(0).withMinute(0)
                .withSecond(0).withNano(0);
        LocalDateTime currentDateTime = LocalDateTime.ofInstant(currentDate.toInstant(),
                ZoneId.systemDefault());
        long seconds = ChronoUnit.SECONDS.between(currentDateTime, midnight);
        return (int) seconds;
    }


    /**
     * 计算年龄
     * @param birthDay
     * @return
     * @throws Exception
     */
    public static Integer calcAge(Date birthDay){
        Long age = timeDiff(new Date(),birthDay)/(365 * 24 * 60 * 60 * 1000L);
        return age.intValue();
    }

    /**
     * 计算是轮回的第几天
     * @param startDay 开始时间
     * @param endDay 结束时间
     * @param roudTime 几天一个轮回
     * @return
     */
    public static int calcRound(String startDay,String endDay,int roudTime){
        Long time = null;
        try {
            time = DateUtils.addDays(DateUtils.parseDate(endDay,yyyy_MM_dd),1).getTime() - DateUtils.parseDate(startDay,yyyy_MM_dd).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Long  residue = time % (roudTime * 24 * 60 * 60 * 1000);
        Long res = residue / (24 * 60 * 60 * 1000);
        if(res.intValue() == 0){
           return  roudTime;
        }
        return res.intValue();
    }

    /**
     * 功能描述: 计算两个日期相隔的小时
     * @param: []
     * @return: java.lang.Long
     * @author: 刘猛
     * @date: 2019/3/21 16:33
     **/
    public static Long getHoursBetweenDate(Date start,Date end){
        return (end.getTime() - start.getTime()) / 1000 / 60 /60;
    }

    /**
     * 功能描述: 计算几周的开始时间和结束时间
     * @param: [count]
     * @return: java.lang.String[]
     * @author: 刘猛
     * @date: 2019/3/21 17:44
     **/
    public static String[] getWeekBetweenDayStr(Integer count,boolean add){
        Integer baseDays = 6;
        if(count <= 0){
            throw new IllegalArgumentException("参数必须大于0！");
        }
        Integer dayCount = 0;
        if(add){
            dayCount = count - 1;
        }else{
            dayCount = 1 - count;
        }

        Date endDate = DateUtils.addDays(new Date(),dayCount * baseDays);
        Date startDate = DateUtils.addDays(DateUtils.addDays(new Date(),(dayCount - 1) * baseDays),1);
        String[] result = new String[2];
        result[0] = DateFormatUtils.format(startDate,yyyy_MM_dd + DAY_START);
        result[1] = DateFormatUtils.format(endDate,yyyy_MM_dd + DAY_END);
        return result;
    }

    public static String[] getDayStartAndEnd(String date){
        String[] rs = new String[2];
        rs[0] = date + DAY_START;
        rs[1] = date + DAY_START;
        return rs;
    }


    /**
     * 获取某年某月的第一天日期
     * @param date
     * @return
     */
   public static Date getStartMonthDate(Date date) {
     Calendar calendar = Calendar.getInstance();
     calendar.setTime(date);
     calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 1);
     return calendar.getTime();
    }

    /**
     * 获取某年某月的最后一天日期
     * @param date
     * @return
     */
   public static Date getEndMonthDate(Date date) {
     Calendar calendar = Calendar.getInstance();
     calendar.setTime(date);
     calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 1);
     int day = calendar.getActualMaximum(5);
     calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), day);
     return calendar.getTime();
    }

    /**
     * 获取当前时间与月初的时间集合
     * @return
     */
    public static List<Integer> getBetweenMonthDays(Date date){
       List<Integer> dayLists = Lists.newArrayList();
       int days = DateUtil.days(date,getStartMonthDate(date)) + 1;
       for (int i = 1;i<= days; i++){
           dayLists.add(i);
       }
       return dayLists;
    }

    public static List<String> getDayTimeStrs(List<Integer> days,Date date){
        List<String> result = Lists.newArrayList();
        days.forEach(day ->{
            result.add(DateFormatUtils.format(DateUtils.addDays(getStartMonthDate(date),day - 1),yyyy_MM_dd));
        });
        return result;
    }

    public static List<String> getBetweenNowMonthDays(){
        return getDayTimeStrs(getBetweenMonthDays(new Date()),new Date());
    }

    public static long timeDiff(Date d1,Date d2){
        return d1.getTime() - d2.getTime();
    }

    public static Timestamp getCurrentTimestamp(){
        return new Timestamp(System.currentTimeMillis());
    }

    public static Date getTodayEndDate(){
        return parse(DateFormatUtils.format(new Date(),yyyy_MM_dd) + " 23:59:59",yyyy_MM_dd_HH_mm_ss);
    }

    public static Long todayRemainTime(TimeUnit unit){
        Long time;
        switch (unit){
            case SECONDS:  time = DateUtil.timeDiff(DateUtil.getTodayEndDate(),new Date())/1000;break;
            case MINUTES:  time = DateUtil.timeDiff(DateUtil.getTodayEndDate(),new Date())/(1000*60);break;
            case MILLISECONDS:  time = DateUtil.timeDiff(DateUtil.getTodayEndDate(),new Date());break;
            default:throw new IllegalArgumentException("时间单位参数错误！");

        }
        return time;
    }

    /**
     * 功能描述: 计算两个日期相隔的天时
     * @methodName getDatePoor
     * @author: 刘猛
     * @date: 2019/6/23 11:00
     * @param: [endDate, nowDate]
     * @return: java.lang.String
     **/
    public static String getDatePoor(Date endDate, Date nowDate) {

        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
//        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
//        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时";
    }
}